home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / ftp / cmds.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-18  |  38.5 KB  |  2,181 lines

  1. /*
  2.  * Copyright (c) 1985, 1989 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifndef lint
  19. static char sccsid[] = "@(#)cmds.c    5.16 (Berkeley) 3/21/89";
  20. #endif /* not lint */
  21.  
  22. /*
  23.  * FTP User Program -- Command Routines.
  24.  */
  25. #include <sys/param.h>
  26. #include <sys/wait.h>
  27. #include <sys/stat.h>
  28. #include <sys/socket.h>
  29.  
  30. #include <arpa/ftp.h>
  31.  
  32. #include <signal.h>
  33. #include <stdio.h>
  34. #include <errno.h>
  35. #include <netdb.h>
  36. #include <ctype.h>
  37. #include <time.h>
  38.  
  39. #include "ftp_var.h"
  40.  
  41.  
  42. extern    char *globerr;
  43. extern    char **glob();
  44. extern    char *home;
  45. extern    char *remglob();
  46. extern    char *getenv();
  47. extern    char *index();
  48. extern    char *rindex();
  49. extern off_t restart_point;
  50. extern char reply_string[];
  51.  
  52. char *mname;
  53. jmp_buf jabort;
  54. char *dotrans(), *domap();
  55.  
  56. /*
  57.  * Connect to peer server and
  58.  * auto-login, if possible.
  59.  */
  60. setpeer(argc, argv)
  61.     int argc;
  62.     char *argv[];
  63. {
  64.     char *host, *hookup();
  65.     int port;
  66.  
  67.     if (connected) {
  68.         printf("Already connected to %s, use close first.\n",
  69.             hostname);
  70.         code = -1;
  71.         return;
  72.     }
  73.     if (argc < 2) {
  74.         (void) strcat(line, " ");
  75.         printf("(to) ");
  76.         (void) gets(&line[strlen(line)]);
  77.         makeargv();
  78.         argc = margc;
  79.         argv = margv;
  80.     }
  81.     if (argc > 3) {
  82.         printf("usage: %s host-name [port]\n", argv[0]);
  83.         code = -1;
  84.         return;
  85.     }
  86.     port = sp->s_port;
  87.     if (argc > 2) {
  88.         port = atoi(argv[2]);
  89.         if (port <= 0) {
  90.             printf("%s: bad port number-- %s\n", argv[1], argv[2]);
  91.             printf ("usage: %s host-name [port]\n", argv[0]);
  92.             code = -1;
  93.             return;
  94.         }
  95.         port = htons(port);
  96.     }
  97.     host = hookup(argv[1], port);
  98.     if (host) {
  99.         connected = 1;
  100.         if (autologin) {
  101.             int overbose;
  102.  
  103.             (void) login(argv[1]);
  104. #if defined(unix) && NBBY == 8
  105. /*
  106.  * this ifdef is to keep someone form "porting" this to an incompatible
  107.  * system and not checking this out. This way they have to think about it.
  108.  */
  109.             overbose = verbose;
  110.             if (debug == 0)
  111.                 verbose = -1;
  112.             if (command("SYST") == COMPLETE && overbose) {
  113.                 register char *cp, c;
  114.                 cp = index(reply_string+4, ' ');
  115.                 if (cp == NULL)
  116.                     cp = index(reply_string+4, '\r');
  117.                 if (cp) {
  118.                     if (cp[-1] == '.')
  119.                         cp--;
  120.                     c = *cp;
  121.                     *cp = '\0';
  122.                 }
  123.  
  124.                 printf("Remote system type is %s.\n",
  125.                     reply_string+4);
  126.                 if (cp)
  127.                     *cp = c;
  128.             }
  129.             if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
  130.                 setbinary();
  131.                 if (overbose)
  132.                     printf("Using %s mode to transfer files.\n",
  133.                     typename);
  134.             } else if (overbose && 
  135.                 !strncmp(reply_string, "215 TOPS20", 10)) {
  136.                 printf(
  137. "Remember to set tenex mode when transfering binary files from this machine.\n");
  138.             }
  139.             verbose = overbose;
  140. #endif /* unix */
  141.         }
  142.     }
  143. }
  144.  
  145. struct    types {
  146.     char    *t_name;
  147.     char    *t_mode;
  148.     int    t_type;
  149.     char    *t_arg;
  150. } types[] = {
  151.     { "ascii",    "A",    TYPE_A,    0 },
  152.     { "binary",    "I",    TYPE_I,    0 },
  153.     { "image",    "I",    TYPE_I,    0 },
  154.     { "ebcdic",    "E",    TYPE_E,    0 },
  155.     { "tenex",    "L",    TYPE_L,    bytename },
  156.     0
  157. };
  158.  
  159. /*
  160.  * Set transfer type.
  161.  */
  162. settype(argc, argv)
  163.     char *argv[];
  164. {
  165.     register struct types *p;
  166.     int comret;
  167.  
  168.     if (argc > 2) {
  169.         char *sep;
  170.  
  171.         printf("usage: %s [", argv[0]);
  172.         sep = " ";
  173.         for (p = types; p->t_name; p++) {
  174.             printf("%s%s", sep, p->t_name);
  175.             if (*sep == ' ')
  176.                 sep = " | ";
  177.         }
  178.         printf(" ]\n");
  179.         code = -1;
  180.         return;
  181.     }
  182.     if (argc < 2) {
  183.         printf("Using %s mode to transfer files.\n", typename);
  184.         code = 0;
  185.         return;
  186.     }
  187.     for (p = types; p->t_name; p++)
  188.         if (strcmp(argv[1], p->t_name) == 0)
  189.             break;
  190.     if (p->t_name == 0) {
  191.         printf("%s: unknown mode\n", argv[1]);
  192.         code = -1;
  193.         return;
  194.     }
  195.     if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
  196.         comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
  197.     else
  198.         comret = command("TYPE %s", p->t_mode);
  199.     if (comret == COMPLETE) {
  200.         (void) strcpy(typename, p->t_name);
  201.         type = p->t_type;
  202.     }
  203. }
  204.  
  205. /*
  206.  * Set binary transfer type.
  207.  */
  208. /*VARARGS*/
  209. setbinary()
  210. {
  211.  
  212.     call(settype, "type", "binary", 0);
  213. }
  214.  
  215. /*
  216.  * Set ascii transfer type.
  217.  */
  218. /*VARARGS*/
  219. setascii()
  220. {
  221.  
  222.     call(settype, "type", "ascii", 0);
  223. }
  224.  
  225. /*
  226.  * Set tenex transfer type.
  227.  */
  228. /*VARARGS*/
  229. settenex()
  230. {
  231.  
  232.     call(settype, "type", "tenex", 0);
  233. }
  234.  
  235. /*
  236.  * Set ebcdic transfer type.
  237.  */
  238. /*VARARGS*/
  239. setebcdic()
  240. {
  241.  
  242.     call(settype, "type", "ebcdic", 0);
  243. }
  244.  
  245. /*
  246.  * Set file transfer mode.
  247.  */
  248. /*ARGSUSED*/
  249. setmode(argc, argv)
  250.     char *argv[];
  251. {
  252.  
  253.     printf("We only support %s mode, sorry.\n", modename);
  254.     code = -1;
  255. }
  256.  
  257. /*
  258.  * Set file transfer format.
  259.  */
  260. /*ARGSUSED*/
  261. setform(argc, argv)
  262.     char *argv[];
  263. {
  264.  
  265.     printf("We only support %s format, sorry.\n", formname);
  266.     code = -1;
  267. }
  268.  
  269. /*
  270.  * Set file transfer structure.
  271.  */
  272. /*ARGSUSED*/
  273. setstruct(argc, argv)
  274.     char *argv[];
  275. {
  276.  
  277.     printf("We only support %s structure, sorry.\n", structname);
  278.     code = -1;
  279. }
  280.  
  281. /*
  282.  * Send a single file.
  283.  */
  284. put(argc, argv)
  285.     int argc;
  286.     char *argv[];
  287. {
  288.     char *cmd;
  289.     int loc = 0;
  290.     char *oldargv1, *oldargv2;
  291.  
  292.     if (argc == 2) {
  293.         argc++;
  294.         argv[2] = argv[1];
  295.         loc++;
  296.     }
  297.     if (argc < 2) {
  298.         (void) strcat(line, " ");
  299.         printf("(local-file) ");
  300.         (void) gets(&line[strlen(line)]);
  301.         makeargv();
  302.         argc = margc;
  303.         argv = margv;
  304.     }
  305.     if (argc < 2) {
  306. usage:
  307.         printf("usage:%s local-file remote-file\n", argv[0]);
  308.         code = -1;
  309.         return;
  310.     }
  311.     if (argc < 3) {
  312.         (void) strcat(line, " ");
  313.         printf("(remote-file) ");
  314.         (void) gets(&line[strlen(line)]);
  315.         makeargv();
  316.         argc = margc;
  317.         argv = margv;
  318.     }
  319.     if (argc < 3) 
  320.         goto usage;
  321.     oldargv1 = argv[1];
  322.     oldargv2 = argv[2];
  323.     if (!globulize(&argv[1])) {
  324.         code = -1;
  325.         return;
  326.     }
  327.     /*
  328.      * If "globulize" modifies argv[1], and argv[2] is a copy of
  329.      * the old argv[1], make it a copy of the new argv[1].
  330.      */
  331.     if (argv[1] != oldargv1 && argv[2] == oldargv1) {
  332.         argv[2] = argv[1];
  333.     }
  334.     cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
  335.     if (loc && ntflag) {
  336.         argv[2] = dotrans(argv[2]);
  337.     }
  338.     if (loc && mapflag) {
  339.         argv[2] = domap(argv[2]);
  340.     }
  341.     sendrequest(cmd, argv[1], argv[2],
  342.         argv[1] != oldargv1 || argv[2] != oldargv2);
  343. }
  344.  
  345. /*
  346.  * Send multiple files.
  347.  */
  348. mput(argc, argv)
  349.     char *argv[];
  350. {
  351.     register int i;
  352.     int ointer, (*oldintr)(), mabort();
  353.     extern jmp_buf jabort;
  354.     char *tp;
  355.  
  356.     if (argc < 2) {
  357.         (void) strcat(line, " ");
  358.         printf("(local-files) ");
  359.         (void) gets(&line[strlen(line)]);
  360.         makeargv();
  361.         argc = margc;
  362.         argv = margv;
  363.     }
  364.     if (argc < 2) {
  365.         printf("usage:%s local-files\n", argv[0]);
  366.         code = -1;
  367.         return;
  368.     }
  369.     mname = argv[0];
  370.     mflag = 1;
  371.     oldintr = signal(SIGINT, mabort);
  372.     (void) setjmp(jabort);
  373.     if (proxy) {
  374.         char *cp, *tp2, tmpbuf[MAXPATHLEN];
  375.  
  376.         while ((cp = remglob(argv,0)) != NULL) {
  377.             if (*cp == 0) {
  378.                 mflag = 0;
  379.                 continue;
  380.             }
  381.             if (mflag && confirm(argv[0], cp)) {
  382.                 tp = cp;
  383.                 if (mcase) {
  384.                     while (*tp && !islower(*tp)) {
  385.                         tp++;
  386.                     }
  387.                     if (!*tp) {
  388.                         tp = cp;
  389.                         tp2 = tmpbuf;
  390.                         while ((*tp2 = *tp) != NULL) {
  391.                              if (isupper(*tp2)) {
  392.                                 *tp2 = 'a' + *tp2 - 'A';
  393.                              }
  394.                              tp++;
  395.                              tp2++;
  396.                         }
  397.                     }
  398.                     tp = tmpbuf;
  399.                 }
  400.                 if (ntflag) {
  401.                     tp = dotrans(tp);
  402.                 }
  403.                 if (mapflag) {
  404.                     tp = domap(tp);
  405.                 }
  406.                 sendrequest((sunique) ? "STOU" : "STOR",
  407.                     cp, tp, cp != tp || !interactive);
  408.                 if (!mflag && fromatty) {
  409.                     ointer = interactive;
  410.                     interactive = 1;
  411.                     if (confirm("Continue with","mput")) {
  412.                         mflag++;
  413.                     }
  414.                     interactive = ointer;
  415.                 }
  416.             }
  417.         }
  418.         (void) signal(SIGINT, oldintr);
  419.         mflag = 0;
  420.         return;
  421.     }
  422.     for (i = 1; i < argc; i++) {
  423.         register char **cpp, **gargs;
  424.  
  425.         if (!doglob) {
  426.             if (mflag && confirm(argv[0], argv[i])) {
  427.                 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
  428.                 tp = (mapflag) ? domap(tp) : tp;
  429.                 sendrequest((sunique) ? "STOU" : "STOR",
  430.                     argv[i], tp, tp != argv[i] || !interactive);
  431.                 if (!mflag && fromatty) {
  432.                     ointer = interactive;
  433.                     interactive = 1;
  434.                     if (confirm("Continue with","mput")) {
  435.                         mflag++;
  436.                     }
  437.                     interactive = ointer;
  438.                 }
  439.             }
  440.             continue;
  441.         }
  442.         gargs = glob(argv[i]);
  443.         if (globerr != NULL) {
  444.             printf("%s\n", globerr);
  445.             if (gargs) {
  446.                 blkfree(gargs);
  447.                 free(gargs);
  448.             }
  449.             continue;
  450.         }
  451.         for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
  452.             if (mflag && confirm(argv[0], *cpp)) {
  453.                 tp = (ntflag) ? dotrans(*cpp) : *cpp;
  454.                 tp = (mapflag) ? domap(tp) : tp;
  455.                 sendrequest((sunique) ? "STOU" : "STOR",
  456.                     *cpp, tp, *cpp != tp || !interactive);
  457.                 if (!mflag && fromatty) {
  458.                     ointer = interactive;
  459.                     interactive = 1;
  460.                     if (confirm("Continue with","mput")) {
  461.                         mflag++;
  462.                     }
  463.                     interactive = ointer;
  464.                 }
  465.             }
  466.         }
  467.         if (gargs != NULL) {
  468. #if 1
  469. /*
  470.  * There is a bug here.  Gargs is an array of pointers and blkfree
  471.  * frees this array.  However, they are not generally malloc'd pointers
  472.  * and thus cannot be freed.  Commenting this out may cause a memory
  473.  * leak in some cases, but keeping it in results in erroneous frees.
  474.  */
  475.             blkfree(gargs);
  476. #endif
  477.             free(gargs);
  478.         }
  479.     }
  480.     (void) signal(SIGINT, oldintr);
  481.     mflag = 0;
  482. }
  483.  
  484. reget(argc, argv)
  485.     char *argv[];
  486. {
  487.     (void) getit(argc, argv, 1, "r+w");
  488. }
  489.  
  490. get(argc, argv)
  491.     char *argv[];
  492. {
  493.     (void) getit(argc, argv, 0, restart_point ? "r+w" : "w" );
  494. }
  495.  
  496. /*
  497.  * Receive one file.
  498.  */
  499. getit(argc, argv, restartit, mode)
  500.     char *argv[];
  501.     char *mode;
  502. {
  503.     int loc = 0;
  504.     char *oldargv1, *oldargv2;
  505.  
  506.     if (argc == 2) {
  507.         argc++;
  508.         argv[2] = argv[1];
  509.         loc++;
  510.     }
  511.     if (argc < 2) {
  512.         (void) strcat(line, " ");
  513.         printf("(remote-file) ");
  514.         (void) gets(&line[strlen(line)]);
  515.         makeargv();
  516.         argc = margc;
  517.         argv = margv;
  518.     }
  519.     if (argc < 2) {
  520. usage:
  521.         printf("usage: %s remote-file [ local-file ]\n", argv[0]);
  522.         code = -1;
  523.         return (0);
  524.     }
  525.     if (argc < 3) {
  526.         (void) strcat(line, " ");
  527.         printf("(local-file) ");
  528.         (void) gets(&line[strlen(line)]);
  529.         makeargv();
  530.         argc = margc;
  531.         argv = margv;
  532.     }
  533.     if (argc < 3) 
  534.         goto usage;
  535.     oldargv1 = argv[1];
  536.     oldargv2 = argv[2];
  537.     if (!globulize(&argv[2])) {
  538.         code = -1;
  539.         return (0);
  540.     }
  541.     if (loc && mcase) {
  542.         char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
  543.  
  544.         while (*tp && !islower(*tp)) {
  545.             tp++;
  546.         }
  547.         if (!*tp) {
  548.             tp = argv[2];
  549.             tp2 = tmpbuf;
  550.             while ((*tp2 = *tp) != NULL) {
  551.                 if (isupper(*tp2)) {
  552.                     *tp2 = 'a' + *tp2 - 'A';
  553.                 }
  554.                 tp++;
  555.                 tp2++;
  556.             }
  557.             argv[2] = tmpbuf;
  558.         }
  559.     }
  560.     if (loc && ntflag)
  561.         argv[2] = dotrans(argv[2]);
  562.     if (loc && mapflag)
  563.         argv[2] = domap(argv[2]);
  564.     if (restartit) {
  565.         struct stat stbuf;
  566.         int ret;
  567.  
  568.         ret = stat(argv[2], &stbuf);
  569.         if (restartit == 1) {
  570.             if (ret < 0) {
  571.                 perror(argv[2]);
  572.                 return (0);
  573.             }
  574.             restart_point = stbuf.st_size;
  575.         } else {
  576.             if (ret == 0) {
  577.                 int overbose;
  578.  
  579.                 overbose = verbose;
  580.                 if (debug == 0)
  581.                     verbose = -1;
  582.                 if (command("MDTM %s", argv[1]) == COMPLETE) {
  583.                     int yy, mo, day, hour, min, sec;
  584.                     struct tm *tm;
  585.                     verbose = overbose;
  586.                     sscanf(reply_string,
  587.                         "%*s %04d%02d%02d%02d%02d%02d",
  588.                         &yy, &mo, &day, &hour, &min, &sec);
  589.                     tm = gmtime(&stbuf.st_mtime);
  590.                     tm->tm_mon++;
  591.                     if (tm->tm_year > yy%100)
  592.                         return (1);
  593.                     else if (tm->tm_year == yy%100) {
  594.                         if (tm->tm_mon > mo)
  595.                             return (1);
  596.                     } else if (tm->tm_mon == mo) {
  597.                         if (tm->tm_mday > day)
  598.                             return (1);
  599.                     } else if (tm->tm_mday == day) {
  600.                         if (tm->tm_hour > hour)
  601.                             return (1);
  602.                     } else if (tm->tm_hour == hour) {
  603.                         if (tm->tm_min > min)
  604.                             return (1);
  605.                     } else if (tm->tm_min == min) {
  606.                         if (tm->tm_sec > sec)
  607.                             return (1);
  608.                     }
  609.                 } else {
  610.                     fputs(reply_string, stdout);
  611.                     verbose = overbose;
  612.                     return (0);
  613.                 }
  614.             }
  615.         }
  616.     }
  617.  
  618.     recvrequest("RETR", argv[2], argv[1], mode,
  619.         argv[1] != oldargv1 || argv[2] != oldargv2);
  620.     restart_point = 0;
  621.     return (0);
  622. }
  623.  
  624. mabort()
  625. {
  626.     int ointer;
  627.     extern jmp_buf jabort;
  628.  
  629.     printf("\n");
  630.     (void) fflush(stdout);
  631.     if (mflag && fromatty) {
  632.         ointer = interactive;
  633.         interactive = 1;
  634.         if (confirm("Continue with", mname)) {
  635.             interactive = ointer;
  636.             longjmp(jabort,0);
  637.         }
  638.         interactive = ointer;
  639.     }
  640.     mflag = 0;
  641.     longjmp(jabort,0);
  642. }
  643.  
  644. /*
  645.  * Get multiple files.
  646.  */
  647. mget(argc, argv)
  648.     char *argv[];
  649. {
  650.     char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
  651.     int ointer, (*oldintr)(), mabort();
  652.     extern jmp_buf jabort;
  653.  
  654.     if (argc < 2) {
  655.         (void) strcat(line, " ");
  656.         printf("(remote-files) ");
  657.         (void) gets(&line[strlen(line)]);
  658.         makeargv();
  659.         argc = margc;
  660.         argv = margv;
  661.     }
  662.     if (argc < 2) {
  663.         printf("usage:%s remote-files\n", argv[0]);
  664.         code = -1;
  665.         return;
  666.     }
  667.     mname = argv[0];
  668.     mflag = 1;
  669.     oldintr = signal(SIGINT,mabort);
  670.     (void) setjmp(jabort);
  671.     while ((cp = remglob(argv,proxy)) != NULL) {
  672.         if (*cp == '\0') {
  673.             mflag = 0;
  674.             continue;
  675.         }
  676.         if (mflag && confirm(argv[0], cp)) {
  677.             tp = cp;
  678.             if (mcase) {
  679.                 while (*tp && !islower(*tp)) {
  680.                     tp++;
  681.                 }
  682.                 if (!*tp) {
  683.                     tp = cp;
  684.                     tp2 = tmpbuf;
  685.                     while ((*tp2 = *tp) != NULL) {
  686.                         if (isupper(*tp2)) {
  687.                             *tp2 = 'a' + *tp2 - 'A';
  688.                         }
  689.                         tp++;
  690.                         tp2++;
  691.                     }
  692.                 }
  693.                 tp = tmpbuf;
  694.             }
  695.             if (ntflag) {
  696.                 tp = dotrans(tp);
  697.             }
  698.             if (mapflag) {
  699.                 tp = domap(tp);
  700.             }
  701.             recvrequest("RETR", tp, cp, "w",
  702.                 tp != cp || !interactive);
  703.             if (!mflag && fromatty) {
  704.                 ointer = interactive;
  705.                 interactive = 1;
  706.                 if (confirm("Continue with","mget")) {
  707.                     mflag++;
  708.                 }
  709.                 interactive = ointer;
  710.             }
  711.         }
  712.     }
  713.     (void) signal(SIGINT,oldintr);
  714.     mflag = 0;
  715. }
  716.  
  717. char *
  718. remglob(argv,doswitch)
  719.     char *argv[];
  720.     int doswitch;
  721. {
  722.     char temp[16];
  723.     static char buf[MAXPATHLEN];
  724.     static FILE *ftemp = NULL;
  725.     static char **args;
  726.     int oldverbose, oldhash;
  727.     char *cp, *mode;
  728.  
  729.     if (!mflag) {
  730.         if (!doglob) {
  731.             args = NULL;
  732.         }
  733.         else {
  734.             if (ftemp) {
  735.                 (void) fclose(ftemp);
  736.                 ftemp = NULL;
  737.             }
  738.         }
  739.         return(NULL);
  740.     }
  741.     if (!doglob) {
  742.         if (args == NULL)
  743.             args = argv;
  744.         if ((cp = *++args) == NULL)
  745.             args = NULL;
  746.         return (cp);
  747.     }
  748.     if (ftemp == NULL) {
  749.         (void) strcpy(temp, "/tmp/ftpXXXXXX");
  750.         (void) mktemp(temp);
  751.         oldverbose = verbose, verbose = 0;
  752.         oldhash = hash, hash = 0;
  753.         if (doswitch) {
  754.             pswitch(!proxy);
  755.         }
  756.         for (mode = "w"; *++argv != NULL; mode = "a")
  757.             recvrequest ("NLST", temp, *argv, mode, 0);
  758.         if (doswitch) {
  759.             pswitch(!proxy);
  760.         }
  761.         verbose = oldverbose; hash = oldhash;
  762.         ftemp = fopen(temp, "r");
  763.         (void) unlink(temp);
  764.         if (ftemp == NULL) {
  765.             printf("can't find list of remote files, oops\n");
  766.             return (NULL);
  767.         }
  768.     }
  769.     if (fgets(buf, sizeof (buf), ftemp) == NULL) {
  770.         (void) fclose(ftemp), ftemp = NULL;
  771.         return (NULL);
  772.     }
  773.     if ((cp = index(buf, '\n')) != NULL)
  774.         *cp = '\0';
  775.     return (buf);
  776. }
  777.  
  778. char *
  779. onoff(bool)
  780.     int bool;
  781. {
  782.  
  783.     return (bool ? "on" : "off");
  784. }
  785.  
  786. /*
  787.  * Show status.
  788.  */
  789. /*ARGSUSED*/
  790. status(argc, argv)
  791.     char *argv[];
  792. {
  793.     int i;
  794.  
  795.     if (connected)
  796.         printf("Connected to %s.\n", hostname);
  797.     else
  798.         printf("Not connected.\n");
  799.     if (!proxy) {
  800.         pswitch(1);
  801.         if (connected) {
  802.             printf("Connected for proxy commands to %s.\n", hostname);
  803.         }
  804.         else {
  805.             printf("No proxy connection.\n");
  806.         }
  807.         pswitch(0);
  808.     }
  809.     printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
  810.         modename, typename, formname, structname);
  811.     printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 
  812.         onoff(verbose), onoff(bell), onoff(interactive),
  813.         onoff(doglob));
  814.     printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
  815.         onoff(runique));
  816.     printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
  817.     if (ntflag) {
  818.         printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
  819.     }
  820.     else {
  821.         printf("Ntrans: off\n");
  822.     }
  823.     if (mapflag) {
  824.         printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
  825.     }
  826.     else {
  827.         printf("Nmap: off\n");
  828.     }
  829.     printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
  830.         onoff(hash), onoff(sendport));
  831.     if (macnum > 0) {
  832.         printf("Macros:\n");
  833.         for (i=0; i<macnum; i++) {
  834.             printf("\t%s\n",macros[i].mac_name);
  835.         }
  836.     }
  837.     code = 0;
  838. }
  839.  
  840. /*
  841.  * Set beep on cmd completed mode.
  842.  */
  843. /*VARARGS*/
  844. setbell()
  845. {
  846.  
  847.     bell = !bell;
  848.     printf("Bell mode %s.\n", onoff(bell));
  849.     code = bell;
  850. }
  851.  
  852. /*
  853.  * Turn on packet tracing.
  854.  */
  855. /*VARARGS*/
  856. settrace()
  857. {
  858.  
  859.     trace = !trace;
  860.     printf("Packet tracing %s.\n", onoff(trace));
  861.     code = trace;
  862. }
  863.  
  864. /*
  865.  * Toggle hash mark printing during transfers.
  866.  */
  867. /*VARARGS*/
  868. sethash()
  869. {
  870.  
  871.     hash = !hash;
  872.     printf("Hash mark printing %s", onoff(hash));
  873.     code = hash;
  874.     if (hash)
  875.         printf(" (%d bytes/hash mark)", 1024);
  876.     printf(".\n");
  877. }
  878.  
  879. /*
  880.  * Turn on printing of server echo's.
  881.  */
  882. /*VARARGS*/
  883. setverbose()
  884. {
  885.  
  886.     verbose = !verbose;
  887.     printf("Verbose mode %s.\n", onoff(verbose));
  888.     code = verbose;
  889. }
  890.  
  891. /*
  892.  * Toggle PORT cmd use before each data connection.
  893.  */
  894. /*VARARGS*/
  895. setport()
  896. {
  897.  
  898.     sendport = !sendport;
  899.     printf("Use of PORT cmds %s.\n", onoff(sendport));
  900.     code = sendport;
  901. }
  902.  
  903. /*
  904.  * Turn on interactive prompting
  905.  * during mget, mput, and mdelete.
  906.  */
  907. /*VARARGS*/
  908. setprompt()
  909. {
  910.  
  911.     interactive = !interactive;
  912.     printf("Interactive mode %s.\n", onoff(interactive));
  913.     code = interactive;
  914. }
  915.  
  916. /*
  917.  * Toggle metacharacter interpretation
  918.  * on local file names.
  919.  */
  920. /*VARARGS*/
  921. setglob()
  922. {
  923.     
  924.     doglob = !doglob;
  925.     printf("Globbing %s.\n", onoff(doglob));
  926.     code = doglob;
  927. }
  928.  
  929. /*
  930.  * Set debugging mode on/off and/or
  931.  * set level of debugging.
  932.  */
  933. /*VARARGS*/
  934. setdebug(argc, argv)
  935.     char *argv[];
  936. {
  937.     int val;
  938.  
  939.     if (argc > 1) {
  940.         val = atoi(argv[1]);
  941.         if (val < 0) {
  942.             printf("%s: bad debugging value.\n", argv[1]);
  943.             code = -1;
  944.             return;
  945.         }
  946.     } else
  947.         val = !debug;
  948.     debug = val;
  949.     if (debug)
  950.         options |= SO_DEBUG;
  951.     else
  952.         options &= ~SO_DEBUG;
  953.     printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
  954.     code = debug > 0;
  955. }
  956.  
  957. /*
  958.  * Set current working directory
  959.  * on remote machine.
  960.  */
  961. cd(argc, argv)
  962.     char *argv[];
  963. {
  964.  
  965.     if (argc < 2) {
  966.         (void) strcat(line, " ");
  967.         printf("(remote-directory) ");
  968.         (void) gets(&line[strlen(line)]);
  969.         makeargv();
  970.         argc = margc;
  971.         argv = margv;
  972.     }
  973.     if (argc < 2) {
  974.         printf("usage:%s remote-directory\n", argv[0]);
  975.         code = -1;
  976.         return;
  977.     }
  978.     if (command("CWD %s", argv[1]) == ERROR && code == 500) {
  979.         if (verbose)
  980.             printf("CWD command not recognized, trying XCWD\n");
  981.         (void) command("XCWD %s", argv[1]);
  982.     }
  983. }
  984.  
  985. /*
  986.  * Set current working directory
  987.  * on local machine.
  988.  */
  989. lcd(argc, argv)
  990.     char *argv[];
  991. {
  992.     char buf[MAXPATHLEN];
  993.  
  994.     if (argc < 2)
  995.         argc++, argv[1] = home;
  996.     if (argc != 2) {
  997.         printf("usage:%s local-directory\n", argv[0]);
  998.         code = -1;
  999.         return;
  1000.     }
  1001.     if (!globulize(&argv[1])) {
  1002.         code = -1;
  1003.         return;
  1004.     }
  1005.     if (chdir(argv[1]) < 0) {
  1006.         perror(argv[1]);
  1007.         code = -1;
  1008.         return;
  1009.     }
  1010.     printf("Local directory now %s\n", getwd(buf));
  1011.     code = 0;
  1012. }
  1013.  
  1014. /*
  1015.  * Delete a single file.
  1016.  */
  1017. delete(argc, argv)
  1018.     char *argv[];
  1019. {
  1020.  
  1021.     if (argc < 2) {
  1022.         (void) strcat(line, " ");
  1023.         printf("(remote-file) ");
  1024.         (void) gets(&line[strlen(line)]);
  1025.         makeargv();
  1026.         argc = margc;
  1027.         argv = margv;
  1028.     }
  1029.     if (argc < 2) {
  1030.         printf("usage:%s remote-file\n", argv[0]);
  1031.         code = -1;
  1032.         return;
  1033.     }
  1034.     (void) command("DELE %s", argv[1]);
  1035. }
  1036.  
  1037. /*
  1038.  * Delete multiple files.
  1039.  */
  1040. mdelete(argc, argv)
  1041.     char *argv[];
  1042. {
  1043.     char *cp;
  1044.     int ointer, (*oldintr)(), mabort();
  1045.     extern jmp_buf jabort;
  1046.  
  1047.     if (argc < 2) {
  1048.         (void) strcat(line, " ");
  1049.         printf("(remote-files) ");
  1050.         (void) gets(&line[strlen(line)]);
  1051.         makeargv();
  1052.         argc = margc;
  1053.         argv = margv;
  1054.     }
  1055.     if (argc < 2) {
  1056.         printf("usage:%s remote-files\n", argv[0]);
  1057.         code = -1;
  1058.         return;
  1059.     }
  1060.     mname = argv[0];
  1061.     mflag = 1;
  1062.     oldintr = signal(SIGINT, mabort);
  1063.     (void) setjmp(jabort);
  1064.     while ((cp = remglob(argv,0)) != NULL) {
  1065.         if (*cp == '\0') {
  1066.             mflag = 0;
  1067.             continue;
  1068.         }
  1069.         if (mflag && confirm(argv[0], cp)) {
  1070.             (void) command("DELE %s", cp);
  1071.             if (!mflag && fromatty) {
  1072.                 ointer = interactive;
  1073.                 interactive = 1;
  1074.                 if (confirm("Continue with", "mdelete")) {
  1075.                     mflag++;
  1076.                 }
  1077.                 interactive = ointer;
  1078.             }
  1079.         }
  1080.     }
  1081.     (void) signal(SIGINT, oldintr);
  1082.     mflag = 0;
  1083. }
  1084.  
  1085. /*
  1086.  * Rename a remote file.
  1087.  */
  1088. renamefile(argc, argv)
  1089.     char *argv[];
  1090. {
  1091.  
  1092.     if (argc < 2) {
  1093.         (void) strcat(line, " ");
  1094.         printf("(from-name) ");
  1095.         (void) gets(&line[strlen(line)]);
  1096.         makeargv();
  1097.         argc = margc;
  1098.         argv = margv;
  1099.     }
  1100.     if (argc < 2) {
  1101. usage:
  1102.         printf("%s from-name to-name\n", argv[0]);
  1103.         code = -1;
  1104.         return;
  1105.     }
  1106.     if (argc < 3) {
  1107.         (void) strcat(line, " ");
  1108.         printf("(to-name) ");
  1109.         (void) gets(&line[strlen(line)]);
  1110.         makeargv();
  1111.         argc = margc;
  1112.         argv = margv;
  1113.     }
  1114.     if (argc < 3) 
  1115.         goto usage;
  1116.     if (command("RNFR %s", argv[1]) == CONTINUE)
  1117.         (void) command("RNTO %s", argv[2]);
  1118. }
  1119.  
  1120. /*
  1121.  * Get a directory listing
  1122.  * of remote files.
  1123.  */
  1124. ls(argc, argv)
  1125.     char *argv[];
  1126. {
  1127.     char *cmd;
  1128.  
  1129.     if (argc < 2)
  1130.         argc++, argv[1] = NULL;
  1131.     if (argc < 3)
  1132.         argc++, argv[2] = "-";
  1133.     if (argc > 3) {
  1134.         printf("usage: %s remote-directory local-file\n", argv[0]);
  1135.         code = -1;
  1136.         return;
  1137.     }
  1138.     cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
  1139.     if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
  1140.         code = -1;
  1141.         return;
  1142.     }
  1143.     if (strcmp(argv[2], "-") && *argv[2] != '|')
  1144.         if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) {
  1145.             code = -1;
  1146.             return;
  1147.     }
  1148.     recvrequest(cmd, argv[2], argv[1], "w", 0);
  1149. }
  1150.  
  1151. /*
  1152.  * Get a directory listing
  1153.  * of multiple remote files.
  1154.  */
  1155. mls(argc, argv)
  1156.     char *argv[];
  1157. {
  1158.     char *cmd, mode[1], *dest;
  1159.     int ointer, i, (*oldintr)(), mabort();
  1160.     extern jmp_buf jabort;
  1161.  
  1162.     if (argc < 2) {
  1163.         (void) strcat(line, " ");
  1164.         printf("(remote-files) ");
  1165.         (void) gets(&line[strlen(line)]);
  1166.         makeargv();
  1167.         argc = margc;
  1168.         argv = margv;
  1169.     }
  1170.     if (argc < 3) {
  1171.         (void) strcat(line, " ");
  1172.         printf("(local-file) ");
  1173.         (void) gets(&line[strlen(line)]);
  1174.         makeargv();
  1175.         argc = margc;
  1176.         argv = margv;
  1177.     }
  1178.     if (argc < 3) {
  1179.         printf("usage:%s remote-files local-file\n", argv[0]);
  1180.         code = -1;
  1181.         return;
  1182.     }
  1183.     dest = argv[argc - 1];
  1184.     argv[argc - 1] = NULL;
  1185.     if (strcmp(dest, "-") && *dest != '|')
  1186.         if (!globulize(&dest) || !confirm("output to local-file:", dest)) {
  1187.             code = -1;
  1188.             return;
  1189.     }
  1190.     cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
  1191.     mname = argv[0];
  1192.     mflag = 1;
  1193.     oldintr = signal(SIGINT, mabort);
  1194.     (void) setjmp(jabort);
  1195.     for (i = 1; mflag && i < argc-1; ++i) {
  1196.         *mode = (i == 1) ? 'w' : 'a';
  1197.         recvrequest(cmd, dest, argv[i], mode, 0);
  1198.         if (!mflag && fromatty) {
  1199.             ointer = interactive;
  1200.             interactive = 1;
  1201.             if (confirm("Continue with", argv[0])) {
  1202.                 mflag ++;
  1203.             }
  1204.             interactive = ointer;
  1205.         }
  1206.     }
  1207.     (void) signal(SIGINT, oldintr);
  1208.     mflag = 0;
  1209. }
  1210.  
  1211. /*
  1212.  * Do a shell escape
  1213.  */
  1214. /*ARGSUSED*/
  1215. shell(argc, argv)
  1216.     char *argv[];
  1217. {
  1218.     int pid, (*old1)(), (*old2)();
  1219.     char shellnam[40], *shell, *namep; 
  1220.     union wait status;
  1221.  
  1222.     old1 = signal (SIGINT, SIG_IGN);
  1223.     old2 = signal (SIGQUIT, SIG_IGN);
  1224.     if ((pid = fork()) == 0) {
  1225.         for (pid = 3; pid < 20; pid++)
  1226.             (void) close(pid);
  1227.         (void) signal(SIGINT, SIG_DFL);
  1228.         (void) signal(SIGQUIT, SIG_DFL);
  1229.         shell = getenv("SHELL");
  1230.         if (shell == NULL)
  1231.             shell = "/bin/sh";
  1232.         namep = rindex(shell,'/');
  1233.         if (namep == NULL)
  1234.             namep = shell;
  1235.         (void) strcpy(shellnam,"-");
  1236.         (void) strcat(shellnam, ++namep);
  1237.         if (strcmp(namep, "sh") != 0)
  1238.             shellnam[0] = '+';
  1239.         if (debug) {
  1240.             printf ("%s\n", shell);
  1241.             (void) fflush (stdout);
  1242.         }
  1243.         if (argc > 1) {
  1244.             execl(shell,shellnam,"-c",altarg,(char *)0);
  1245.         }
  1246.         else {
  1247.             execl(shell,shellnam,(char *)0);
  1248.         }
  1249.         perror(shell);
  1250.         code = -1;
  1251.         exit(1);
  1252.         }
  1253.     if (pid > 0)
  1254.         while (wait(&status) != pid)
  1255.             ;
  1256.     (void) signal(SIGINT, old1);
  1257.     (void) signal(SIGQUIT, old2);
  1258.     if (pid == -1) {
  1259.         perror("Try again later");
  1260.         code = -1;
  1261.     }
  1262.     else {
  1263.         code = 0;
  1264.     }
  1265.     return (0);
  1266. }
  1267.  
  1268. /*
  1269.  * Send new user information (re-login)
  1270.  */
  1271. user(argc, argv)
  1272.     int argc;
  1273.     char **argv;
  1274. {
  1275.     char acct[80], *getpass();
  1276.     int n, aflag = 0;
  1277.  
  1278.     if (argc < 2) {
  1279.         (void) strcat(line, " ");
  1280.         printf("(username) ");
  1281.         (void) gets(&line[strlen(line)]);
  1282.         makeargv();
  1283.         argc = margc;
  1284.         argv = margv;
  1285.     }
  1286.     if (argc > 4) {
  1287.         printf("usage: %s username [password] [account]\n", argv[0]);
  1288.         code = -1;
  1289.         return (0);
  1290.     }
  1291.     n = command("USER %s", argv[1]);
  1292.     if (n == CONTINUE) {
  1293.         if (argc < 3 )
  1294.             argv[2] = getpass("Password: "), argc++;
  1295.         n = command("PASS %s", argv[2]);
  1296.     }
  1297.     if (n == CONTINUE) {
  1298.         if (argc < 4) {
  1299.             printf("Account: "); (void) fflush(stdout);
  1300.             (void) fgets(acct, sizeof(acct) - 1, stdin);
  1301.             acct[strlen(acct) - 1] = '\0';
  1302.             argv[3] = acct; argc++;
  1303.         }
  1304.         n = command("ACCT %s", argv[3]);
  1305.         aflag++;
  1306.     }
  1307.     if (n != COMPLETE) {
  1308.         fprintf(stdout, "Login failed.\n");
  1309.         return (0);
  1310.     }
  1311.     if (!aflag && argc == 4) {
  1312.         (void) command("ACCT %s", argv[3]);
  1313.     }
  1314.     return (1);
  1315. }
  1316.  
  1317. /*
  1318.  * Print working directory.
  1319.  */
  1320. /*VARARGS*/
  1321. pwd()
  1322. {
  1323.     int oldverbose = verbose;
  1324.  
  1325.     /*
  1326.      * If we aren't verbose, this doesn't do anything!
  1327.      */
  1328.     verbose = 1;
  1329.     if (command("PWD") == ERROR && code == 500) {
  1330.         printf("PWD command not recognized, trying XPWD\n");
  1331.         (void) command("XPWD");
  1332.     }
  1333.     verbose = oldverbose;
  1334. }
  1335.  
  1336. /*
  1337.  * Make a directory.
  1338.  */
  1339. makedir(argc, argv)
  1340.     char *argv[];
  1341. {
  1342.  
  1343.     if (argc < 2) {
  1344.         (void) strcat(line, " ");
  1345.         printf("(directory-name) ");
  1346.         (void) gets(&line[strlen(line)]);
  1347.         makeargv();
  1348.         argc = margc;
  1349.         argv = margv;
  1350.     }
  1351.     if (argc < 2) {
  1352.         printf("usage: %s directory-name\n", argv[0]);
  1353.         code = -1;
  1354.         return;
  1355.     }
  1356.     if (command("MKD %s", argv[1]) == ERROR && code == 500) {
  1357.         if (verbose)
  1358.             printf("MKD command not recognized, trying XMKD\n");
  1359.         (void) command("XMKD %s", argv[1]);
  1360.     }
  1361. }
  1362.  
  1363. /*
  1364.  * Remove a directory.
  1365.  */
  1366. removedir(argc, argv)
  1367.     char *argv[];
  1368. {
  1369.  
  1370.     if (argc < 2) {
  1371.         (void) strcat(line, " ");
  1372.         printf("(directory-name) ");
  1373.         (void) gets(&line[strlen(line)]);
  1374.         makeargv();
  1375.         argc = margc;
  1376.         argv = margv;
  1377.     }
  1378.     if (argc < 2) {
  1379.         printf("usage: %s directory-name\n", argv[0]);
  1380.         code = -1;
  1381.         return;
  1382.     }
  1383.     if (command("RMD %s", argv[1]) == ERROR && code == 500) {
  1384.         if (verbose)
  1385.             printf("RMD command not recognized, trying XRMD\n");
  1386.         (void) command("XRMD %s", argv[1]);
  1387.     }
  1388. }
  1389.  
  1390. /*
  1391.  * Send a line, verbatim, to the remote machine.
  1392.  */
  1393. quote(argc, argv)
  1394.     char *argv[];
  1395. {
  1396.     int i;
  1397.     char buf[BUFSIZ];
  1398.  
  1399.     if (argc < 2) {
  1400.         (void) strcat(line, " ");
  1401.         printf("(command line to send) ");
  1402.         (void) gets(&line[strlen(line)]);
  1403.         makeargv();
  1404.         argc = margc;
  1405.         argv = margv;
  1406.     }
  1407.     if (argc < 2) {
  1408.         printf("usage: %s line-to-send\n", argv[0]);
  1409.         code = -1;
  1410.         return;
  1411.     }
  1412.     (void) strcpy(buf, argv[1]);
  1413.     for (i = 2; i < argc; i++) {
  1414.         (void) strcat(buf, " ");
  1415.         (void) strcat(buf, argv[i]);
  1416.     }
  1417.     if (command(buf) == PRELIM) {
  1418.         while (getreply(0) == PRELIM);
  1419.     }
  1420. }
  1421.  
  1422. /*
  1423.  * Send a SITE command to the remote machine.  The line
  1424.  * is sent almost verbatim to the remote machine, the
  1425.  * first argument is changed to SITE.
  1426.  */
  1427.  
  1428. site(argc, argv)
  1429.     char *argv[];
  1430. {
  1431.     int i;
  1432.     char buf[BUFSIZ];
  1433.  
  1434.     if (argc < 2) {
  1435.         (void) strcat(line, " ");
  1436.         printf("(arguments to SITE command) ");
  1437.         (void) gets(&line[strlen(line)]);
  1438.         makeargv();
  1439.         argc = margc;
  1440.         argv = margv;
  1441.     }
  1442.     if (argc < 2) {
  1443.         printf("usage: %s line-to-send\n", argv[0]);
  1444.         code = -1;
  1445.         return;
  1446.     }
  1447.     (void) strcpy(buf, "SITE ");
  1448.     (void) strcat(buf, argv[1]);
  1449.     for (i = 2; i < argc; i++) {
  1450.         (void) strcat(buf, " ");
  1451.         (void) strcat(buf, argv[i]);
  1452.     }
  1453.     if (command(buf) == PRELIM) {
  1454.         while (getreply(0) == PRELIM);
  1455.     }
  1456. }
  1457.  
  1458. do_chmod(argc, argv)
  1459.     char *argv[];
  1460. {
  1461.     if (argc == 2) {
  1462.         printf("usage: %s mode file-name\n", argv[0]);
  1463.         code = -1;
  1464.         return;
  1465.     }
  1466.     if (argc < 3) {
  1467.         (void) strcat(line, " ");
  1468.         printf("(mode and file-name) ");
  1469.         (void) gets(&line[strlen(line)]);
  1470.         makeargv();
  1471.         argc = margc;
  1472.         argv = margv;
  1473.     }
  1474.     if (argc != 3) {
  1475.         printf("usage: %s mode file-name\n", argv[0]);
  1476.         code = -1;
  1477.         return;
  1478.     }
  1479.     (void)command("SITE CHMOD %s %s", argv[1], argv[2]);
  1480. }
  1481.  
  1482. do_umask(argc, argv)
  1483.     char *argv[];
  1484. {
  1485.     int oldverbose = verbose;
  1486.  
  1487.     verbose = 1;
  1488.     (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
  1489.     verbose = oldverbose;
  1490. }
  1491.  
  1492. idle(argc, argv)
  1493.     char *argv[];
  1494. {
  1495.     int oldverbose = verbose;
  1496.  
  1497.     verbose = 1;
  1498.     (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
  1499.     verbose = oldverbose;
  1500. }
  1501.  
  1502. /*
  1503.  * Ask the other side for help.
  1504.  */
  1505. rmthelp(argc, argv)
  1506.     char *argv[];
  1507. {
  1508.     int oldverbose = verbose;
  1509.  
  1510.     verbose = 1;
  1511.     (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
  1512.     verbose = oldverbose;
  1513. }
  1514.  
  1515. /*
  1516.  * Terminate session and exit.
  1517.  */
  1518. /*VARARGS*/
  1519. quit()
  1520. {
  1521.  
  1522.     if (connected)
  1523.         disconnect();
  1524.     pswitch(1);
  1525.     if (connected) {
  1526.         disconnect();
  1527.     }
  1528.     exit(0);
  1529. }
  1530.  
  1531. /*
  1532.  * Terminate session, but don't exit.
  1533.  */
  1534. disconnect()
  1535. {
  1536.     extern FILE *cout;
  1537.     extern int data;
  1538.  
  1539.     if (!connected)
  1540.         return;
  1541.     (void) command("QUIT");
  1542.     if (cout) {
  1543.         (void) fclose(cout);
  1544.     }
  1545.     cout = NULL;
  1546.     connected = 0;
  1547.     data = -1;
  1548.     if (!proxy) {
  1549.         macnum = 0;
  1550.     }
  1551. }
  1552.  
  1553. confirm(cmd, file)
  1554.     char *cmd, *file;
  1555. {
  1556.     char line[BUFSIZ];
  1557.  
  1558.     if (!interactive)
  1559.         return (1);
  1560.     printf("%s %s? ", cmd, file);
  1561.     (void) fflush(stdout);
  1562.     (void) gets(line);
  1563.     return (*line != 'n' && *line != 'N');
  1564. }
  1565.  
  1566. fatal(msg)
  1567.     char *msg;
  1568. {
  1569.  
  1570.     fprintf(stderr, "ftp: %s\n", msg);
  1571.     exit(1);
  1572. }
  1573.  
  1574. /*
  1575.  * Glob a local file name specification with
  1576.  * the expectation of a single return value.
  1577.  * Can't control multiple values being expanded
  1578.  * from the expression, we return only the first.
  1579.  */
  1580. globulize(cpp)
  1581.     char **cpp;
  1582. {
  1583.     char **globbed;
  1584.  
  1585.     if (!doglob)
  1586.         return (1);
  1587.     globbed = glob(*cpp);
  1588.     if (globerr != NULL) {
  1589.         printf("%s: %s\n", *cpp, globerr);
  1590.         if (globbed) {
  1591.             blkfree(globbed);
  1592.             free(globbed);
  1593.         }
  1594.         return (0);
  1595.     }
  1596.     if (globbed) {
  1597.         *cpp = *globbed++;
  1598.         /* don't waste too much memory */
  1599.         if (*globbed) {
  1600.             blkfree(globbed);
  1601.             free(globbed);
  1602.         }
  1603.     }
  1604.     return (1);
  1605. }
  1606.  
  1607. account(argc,argv)
  1608.     int argc;
  1609.     char **argv;
  1610. {
  1611.     char acct[50], *getpass(), *ap;
  1612.  
  1613.     if (argc > 1) {
  1614.         ++argv;
  1615.         --argc;
  1616.         (void) strncpy(acct,*argv,49);
  1617.         acct[49] = '\0';
  1618.         while (argc > 1) {
  1619.             --argc;
  1620.             ++argv;
  1621.             (void) strncat(acct,*argv, 49-strlen(acct));
  1622.         }
  1623.         ap = acct;
  1624.     }
  1625.     else {
  1626.         ap = getpass("Account:");
  1627.     }
  1628.     (void) command("ACCT %s", ap);
  1629. }
  1630.  
  1631. jmp_buf abortprox;
  1632.  
  1633. proxabort()
  1634. {
  1635.     extern int proxy;
  1636.  
  1637.     if (!proxy) {
  1638.         pswitch(1);
  1639.     }
  1640.     if (connected) {
  1641.         proxflag = 1;
  1642.     }
  1643.     else {
  1644.         proxflag = 0;
  1645.     }
  1646.     pswitch(0);
  1647.     longjmp(abortprox,1);
  1648. }
  1649.  
  1650. doproxy(argc,argv)
  1651.     int argc;
  1652.     char *argv[];
  1653. {
  1654.     int (*oldintr)(), proxabort();
  1655.     register struct cmd *c;
  1656.     struct cmd *getcmd();
  1657.     extern struct cmd cmdtab[];
  1658.     extern jmp_buf abortprox;
  1659.  
  1660.     if (argc < 2) {
  1661.         (void) strcat(line, " ");
  1662.         printf("(command) ");
  1663.         (void) gets(&line[strlen(line)]);
  1664.         makeargv();
  1665.         argc = margc;
  1666.         argv = margv;
  1667.     }
  1668.     if (argc < 2) {
  1669.         printf("usage:%s command\n", argv[0]);
  1670.         code = -1;
  1671.         return;
  1672.     }
  1673.     c = getcmd(argv[1]);
  1674.     if (c == (struct cmd *) -1) {
  1675.         printf("?Ambiguous command\n");
  1676.         (void) fflush(stdout);
  1677.         code = -1;
  1678.         return;
  1679.     }
  1680.     if (c == 0) {
  1681.         printf("?Invalid command\n");
  1682.         (void) fflush(stdout);
  1683.         code = -1;
  1684.         return;
  1685.     }
  1686.     if (!c->c_proxy) {
  1687.         printf("?Invalid proxy command\n");
  1688.         (void) fflush(stdout);
  1689.         code = -1;
  1690.         return;
  1691.     }
  1692.     if (setjmp(abortprox)) {
  1693.         code = -1;
  1694.         return;
  1695.     }
  1696.     oldintr = signal(SIGINT, proxabort);
  1697.     pswitch(1);
  1698.     if (c->c_conn && !connected) {
  1699.         printf("Not connected\n");
  1700.         (void) fflush(stdout);
  1701.         pswitch(0);
  1702.         (void) signal(SIGINT, oldintr);
  1703.         code = -1;
  1704.         return;
  1705.     }
  1706.     (*c->c_handler)(argc-1, argv+1);
  1707.     if (connected) {
  1708.         proxflag = 1;
  1709.     }
  1710.     else {
  1711.         proxflag = 0;
  1712.     }
  1713.     pswitch(0);
  1714.     (void) signal(SIGINT, oldintr);
  1715. }
  1716.  
  1717. setcase()
  1718. {
  1719.     mcase = !mcase;
  1720.     printf("Case mapping %s.\n", onoff(mcase));
  1721.     code = mcase;
  1722. }
  1723.  
  1724. setcr()
  1725. {
  1726.     crflag = !crflag;
  1727.     printf("Carriage Return stripping %s.\n", onoff(crflag));
  1728.     code = crflag;
  1729. }
  1730.  
  1731. setntrans(argc,argv)
  1732.     int argc;
  1733.     char *argv[];
  1734. {
  1735.     if (argc == 1) {
  1736.         ntflag = 0;
  1737.         printf("Ntrans off.\n");
  1738.         code = ntflag;
  1739.         return;
  1740.     }
  1741.     ntflag++;
  1742.     code = ntflag;
  1743.     (void) strncpy(ntin, argv[1], 16);
  1744.     ntin[16] = '\0';
  1745.     if (argc == 2) {
  1746.         ntout[0] = '\0';
  1747.         return;
  1748.     }
  1749.     (void) strncpy(ntout, argv[2], 16);
  1750.     ntout[16] = '\0';
  1751. }
  1752.  
  1753. char *
  1754. dotrans(name)
  1755.     char *name;
  1756. {
  1757.     static char new[MAXPATHLEN];
  1758.     char *cp1, *cp2 = new;
  1759.     register int i, ostop, found;
  1760.  
  1761.     for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++);
  1762.     for (cp1 = name; *cp1; cp1++) {
  1763.         found = 0;
  1764.         for (i = 0; *(ntin + i) && i < 16; i++) {
  1765.             if (*cp1 == *(ntin + i)) {
  1766.                 found++;
  1767.                 if (i < ostop) {
  1768.                     *cp2++ = *(ntout + i);
  1769.                 }
  1770.                 break;
  1771.             }
  1772.         }
  1773.         if (!found) {
  1774.             *cp2++ = *cp1;
  1775.         }
  1776.     }
  1777.     *cp2 = '\0';
  1778.     return(new);
  1779. }
  1780.  
  1781. setnmap(argc, argv)
  1782.     int argc;
  1783.     char *argv[];
  1784. {
  1785.     char *cp;
  1786.  
  1787.     if (argc == 1) {
  1788.         mapflag = 0;
  1789.         printf("Nmap off.\n");
  1790.         code = mapflag;
  1791.         return;
  1792.     }
  1793.     if (argc < 3) {
  1794.         (void) strcat(line, " ");
  1795.         printf("(mapout) ");
  1796.         (void) gets(&line[strlen(line)]);
  1797.         makeargv();
  1798.         argc = margc;
  1799.         argv = margv;
  1800.     }
  1801.     if (argc < 3) {
  1802.         printf("Usage: %s [mapin mapout]\n",argv[0]);
  1803.         code = -1;
  1804.         return;
  1805.     }
  1806.     mapflag = 1;
  1807.     code = 1;
  1808.     cp = index(altarg, ' ');
  1809.     if (proxy) {
  1810.         while(*++cp == ' ');
  1811.         altarg = cp;
  1812.         cp = index(altarg, ' ');
  1813.     }
  1814.     *cp = '\0';
  1815.     (void) strncpy(mapin, altarg, MAXPATHLEN - 1);
  1816.     while (*++cp == ' ');
  1817.     (void) strncpy(mapout, cp, MAXPATHLEN - 1);
  1818. }
  1819.  
  1820. char *
  1821. domap(name)
  1822.     char *name;
  1823. {
  1824.     static char new[MAXPATHLEN];
  1825.     register char *cp1 = name, *cp2 = mapin;
  1826.     char *tp[9], *te[9];
  1827.     int i, toks[9], toknum = 0, match = 1;
  1828.  
  1829.     for (i=0; i < 9; ++i) {
  1830.         toks[i] = 0;
  1831.     }
  1832.     while (match && *cp1 && *cp2) {
  1833.         switch (*cp2) {
  1834.             case '\\':
  1835.                 if (*++cp2 != *cp1) {
  1836.                     match = 0;
  1837.                 }
  1838.                 break;
  1839.             case '$':
  1840.                 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
  1841.                     if (*cp1 != *(++cp2+1)) {
  1842.                         toks[toknum = *cp2 - '1']++;
  1843.                         tp[toknum] = cp1;
  1844.                         while (*++cp1 && *(cp2+1)
  1845.                             != *cp1);
  1846.                         te[toknum] = cp1;
  1847.                     }
  1848.                     cp2++;
  1849.                     break;
  1850.                 }
  1851.                 /* FALLTHROUGH */
  1852.             default:
  1853.                 if (*cp2 != *cp1) {
  1854.                     match = 0;
  1855.                 }
  1856.                 break;
  1857.         }
  1858.         if (match && *cp1) {
  1859.             cp1++;
  1860.         }
  1861.         if (match && *cp2) {
  1862.             cp2++;
  1863.         }
  1864.     }
  1865.     if (!match && *cp1) /* last token mismatch */
  1866.     {
  1867.         toks[toknum] = 0;
  1868.     }
  1869.     cp1 = new;
  1870.     *cp1 = '\0';
  1871.     cp2 = mapout;
  1872.     while (*cp2) {
  1873.         match = 0;
  1874.         switch (*cp2) {
  1875.             case '\\':
  1876.                 if (*(cp2 + 1)) {
  1877.                     *cp1++ = *++cp2;
  1878.                 }
  1879.                 break;
  1880.             case '[':
  1881. LOOP:
  1882.                 if (*++cp2 == '$' && isdigit(*(cp2+1))) { 
  1883.                     if (*++cp2 == '0') {
  1884.                         char *cp3 = name;
  1885.  
  1886.                         while (*cp3) {
  1887.                             *cp1++ = *cp3++;
  1888.                         }
  1889.                         match = 1;
  1890.                     }
  1891.                     else if (toks[toknum = *cp2 - '1']) {
  1892.                         char *cp3 = tp[toknum];
  1893.  
  1894.                         while (cp3 != te[toknum]) {
  1895.                             *cp1++ = *cp3++;
  1896.                         }
  1897.                         match = 1;
  1898.                     }
  1899.                 }
  1900.                 else {
  1901.                     while (*cp2 && *cp2 != ',' && 
  1902.                         *cp2 != ']') {
  1903.                         if (*cp2 == '\\') {
  1904.                             cp2++;
  1905.                         }
  1906.                         else if (*cp2 == '$' &&
  1907.                                    isdigit(*(cp2+1))) {
  1908.                             if (*++cp2 == '0') {
  1909.                                char *cp3 = name;
  1910.  
  1911.                                while (*cp3) {
  1912.                                 *cp1++ = *cp3++;
  1913.                                }
  1914.                             }
  1915.                             else if (toks[toknum =
  1916.                                 *cp2 - '1']) {
  1917.                                char *cp3=tp[toknum];
  1918.  
  1919.                                while (cp3 !=
  1920.                                   te[toknum]) {
  1921.                                 *cp1++ = *cp3++;
  1922.                                }
  1923.                             }
  1924.                         }
  1925.                         else if (*cp2) {
  1926.                             *cp1++ = *cp2++;
  1927.                         }
  1928.                     }
  1929.                     if (!*cp2) {
  1930.                         printf("nmap: unbalanced brackets\n");
  1931.                         return(name);
  1932.                     }
  1933.                     match = 1;
  1934.                     cp2--;
  1935.                 }
  1936.                 if (match) {
  1937.                     while (*++cp2 && *cp2 != ']') {
  1938.                           if (*cp2 == '\\' && *(cp2 + 1)) {
  1939.                             cp2++;
  1940.                           }
  1941.                     }
  1942.                     if (!*cp2) {
  1943.                         printf("nmap: unbalanced brackets\n");
  1944.                         return(name);
  1945.                     }
  1946.                     break;
  1947.                 }
  1948.                 switch (*++cp2) {
  1949.                     case ',':
  1950.                         goto LOOP;
  1951.                     case ']':
  1952.                         break;
  1953.                     default:
  1954.                         cp2--;
  1955.                         goto LOOP;
  1956.                 }
  1957.                 break;
  1958.             case '$':
  1959.                 if (isdigit(*(cp2 + 1))) {
  1960.                     if (*++cp2 == '0') {
  1961.                         char *cp3 = name;
  1962.  
  1963.                         while (*cp3) {
  1964.                             *cp1++ = *cp3++;
  1965.                         }
  1966.                     }
  1967.                     else if (toks[toknum = *cp2 - '1']) {
  1968.                         char *cp3 = tp[toknum];
  1969.  
  1970.                         while (cp3 != te[toknum]) {
  1971.                             *cp1++ = *cp3++;
  1972.                         }
  1973.                     }
  1974.                     break;
  1975.                 }
  1976.                 /* intentional drop through */
  1977.             default:
  1978.                 *cp1++ = *cp2;
  1979.                 break;
  1980.         }
  1981.         cp2++;
  1982.     }
  1983.     *cp1 = '\0';
  1984.     if (!*new) {
  1985.         return(name);
  1986.     }
  1987.     return(new);
  1988. }
  1989.  
  1990. setsunique()
  1991. {
  1992.     sunique = !sunique;
  1993.     printf("Store unique %s.\n", onoff(sunique));
  1994.     code = sunique;
  1995. }
  1996.  
  1997. setrunique()
  1998. {
  1999.     runique = !runique;
  2000.     printf("Receive unique %s.\n", onoff(runique));
  2001.     code = runique;
  2002. }
  2003.  
  2004. /* change directory to perent directory */
  2005. cdup()
  2006. {
  2007.     if (command("CDUP") == ERROR && code == 500) {
  2008.         if (verbose)
  2009.             printf("CDUP command not recognized, trying XCUP\n");
  2010.         (void) command("XCUP");
  2011.     }
  2012. }
  2013.  
  2014. /* restart transfer at specific point */
  2015. restart(argc, argv)
  2016.     int argc;
  2017.     char *argv[];
  2018. {
  2019.     extern long atol();
  2020.     if (argc != 2)
  2021.         printf("restart: offset not specified\n");
  2022.     else {
  2023.         restart_point = atol(argv[1]);
  2024.         printf("restarting at %ld. %s\n", restart_point,
  2025.             "execute get, put or append to initiate transfer");
  2026.     }
  2027. }
  2028.  
  2029. /* show remote system type */
  2030. syst()
  2031. {
  2032.     (void) command("SYST");
  2033. }
  2034.  
  2035. macdef(argc, argv)
  2036.     int argc;
  2037.     char *argv[];
  2038. {
  2039.     char *tmp;
  2040.     int c;
  2041.  
  2042.     if (macnum == 16) {
  2043.         printf("Limit of 16 macros have already been defined\n");
  2044.         code = -1;
  2045.         return;
  2046.     }
  2047.     if (argc < 2) {
  2048.         (void) strcat(line, " ");
  2049.         printf("(macro name) ");
  2050.         (void) gets(&line[strlen(line)]);
  2051.         makeargv();
  2052.         argc = margc;
  2053.         argv = margv;
  2054.     }
  2055.     if (argc != 2) {
  2056.         printf("Usage: %s macro_name\n",argv[0]);
  2057.         code = -1;
  2058.         return;
  2059.     }
  2060.     if (interactive) {
  2061.         printf("Enter macro line by line, terminating it with a null line\n");
  2062.     }
  2063.     (void) strncpy(macros[macnum].mac_name, argv[1], 8);
  2064.     if (macnum == 0) {
  2065.         macros[macnum].mac_start = macbuf;
  2066.     }
  2067.     else {
  2068.         macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
  2069.     }
  2070.     tmp = macros[macnum].mac_start;
  2071.     while (tmp != macbuf+4096) {
  2072.         if ((c = getchar()) == EOF) {
  2073.             printf("macdef:end of file encountered\n");
  2074.             code = -1;
  2075.             return;
  2076.         }
  2077.         if ((*tmp = c) == '\n') {
  2078.             if (tmp == macros[macnum].mac_start) {
  2079.                 macros[macnum++].mac_end = tmp;
  2080.                 code = 0;
  2081.                 return;
  2082.             }
  2083.             if (*(tmp-1) == '\0') {
  2084.                 macros[macnum++].mac_end = tmp - 1;
  2085.                 code = 0;
  2086.                 return;
  2087.             }
  2088.             *tmp = '\0';
  2089.         }
  2090.         tmp++;
  2091.     }
  2092.     while (1) {
  2093.         while ((c = getchar()) != '\n' && c != EOF)
  2094.             /* LOOP */;
  2095.         if (c == EOF || getchar() == '\n') {
  2096.             printf("Macro not defined - 4k buffer exceeded\n");
  2097.             code = -1;
  2098.             return;
  2099.         }
  2100.     }
  2101. }
  2102.  
  2103. /*
  2104.  * get size of file on remote machine
  2105.  */
  2106. sizecmd(argc, argv)
  2107.     char *argv[];
  2108. {
  2109.  
  2110.     if (argc < 2) {
  2111.         (void) strcat(line, " ");
  2112.         printf("(filename) ");
  2113.         (void) gets(&line[strlen(line)]);
  2114.         makeargv();
  2115.         argc = margc;
  2116.         argv = margv;
  2117.     }
  2118.     if (argc < 2) {
  2119.         printf("usage:%s filename\n", argv[0]);
  2120.         code = -1;
  2121.         return;
  2122.     }
  2123.     (void) command("SIZE %s", argv[1]);
  2124. }
  2125.  
  2126. /*
  2127.  * get last modification time of file on remote machine
  2128.  */
  2129. modtime(argc, argv)
  2130.     char *argv[];
  2131. {
  2132.     int overbose;
  2133.  
  2134.     if (argc < 2) {
  2135.         (void) strcat(line, " ");
  2136.         printf("(filename) ");
  2137.         (void) gets(&line[strlen(line)]);
  2138.         makeargv();
  2139.         argc = margc;
  2140.         argv = margv;
  2141.     }
  2142.     if (argc < 2) {
  2143.         printf("usage:%s filename\n", argv[0]);
  2144.         code = -1;
  2145.         return;
  2146.     }
  2147.     overbose = verbose;
  2148.     if (debug == 0)
  2149.         verbose = -1;
  2150.     if (command("MDTM %s", argv[1]) == COMPLETE) {
  2151.         int yy, mo, day, hour, min, sec;
  2152.         sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
  2153.             &day, &hour, &min, &sec);
  2154.         /* might want to print this in local time */
  2155.         printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
  2156.             mo, day, yy, hour, min, sec);
  2157.     } else
  2158.         fputs(reply_string, stdout);
  2159.     verbose = overbose;
  2160. }
  2161.  
  2162. /*
  2163.  * show status on reomte machine
  2164.  */
  2165. rmtstatus(argc, argv)
  2166.     char *argv[];
  2167. {
  2168.     (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
  2169. }
  2170.  
  2171. /*
  2172.  * get file if modtime is more recent than current file
  2173.  */
  2174. newer(argc, argv)
  2175.     char *argv[];
  2176. {
  2177.     if (getit(argc, argv, -1, "w"))
  2178.         printf("Local file \"%s\" is newer than remote file \"%s\"\n",
  2179.             argv[1], argv[2]);
  2180. }
  2181.